
package rawengine.sound.OpenAL;

import static org.lwjgl.openal.AL10.*;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;


public class OpenALSource{
// static
  /** Maximal count of sources. */
  protected static final int MAX_SOURCES = 64;

  /** IntBuffer of all available sources. */
  private static IntBuffer sources;
  
 
  /**
   * Set the reference distance, the roll off factor and the maximal distance of the source.
   *
   * @param id the id of the source
   */
  private void setSoundEnvironment(int id){
	   alSourcef(id, AL_REFERENCE_DISTANCE, 100.0f);
	   alSourcef(id, AL_ROLLOFF_FACTOR, 0.5f);
	   alSourcef(id, AL_MAX_DISTANCE, 1000);
    
    
  }     

  /**
   * Resets properties of the source.
   *
   * @param id the id of the source
   */
  public static void resetSource(int id){
    alSourcef(id, AL_GAIN, 1);
  }

  /**
   * Allocate all available sources.
   */
  
  public static OpenALSource[] alGenSoureces(int numberSources)
  {
	    
	  	OpenALSource[] openSources = new OpenALSource[numberSources];
	  	
	    sources = OpenALUtils.createIntBuffer(numberSources);
	    
	    alGenSources(sources);
	    if(alGetError() == AL_NO_ERROR)
	    	  return null;
	    
	    for(int i=0; i<openSources.length; i++)
	    {
		    openSources[i] = new OpenALSource();
		    
		    int index = sources.get(i);
		    
		    openSources[i].setSoundEnvironment(index);
		    openSources[i].winControl(index);
	    }
	    
	    return openSources;

  }

  /**
   * Frees all allocated sources.
   */
  
  public static void alDeleteSoureces(){
    // free all allocated sources
    alDeleteSources(sources);
  }
 
  // non static
  /** The source id (name). */
  private int id;
  /** Do I have the control over the source? Can I play some waves now? */
  private boolean hasControl = false;

  /**
   * Creates an openAL source.
   */
  public OpenALSource()
  {
	 
		  
	  // allocate all available sources
	   
  }

  /**
   * Return the id of the source.
   *
   * @return id of the source
   */
  public int getId()
  {
    return id;
  }

  /**
   * Try to get control over an unused source.
   *
   * @return true if we have now control over an source
   */

  public boolean bind()
  {
    if(hasControl)
    {
    	return true;
    }

    
      int state = getPropi(AL_SOURCE_STATE);
      if(state != AL_PLAYING && state != AL_PAUSED)
      {
        // we've found an unused source
        int id = getId();
        loseControl();
        resetSource(id);
        this.winControl(id);
        this.setPropf(AL_GAIN, 1);
        
       // System.out.println("Local ID: " +          id);
       // System.out.println("Classe ID: " + this.id);
        
        return true;
      }
  
    System.out.println("no sound source available");
    return false;
  }


  /**
   * The openALSource get control over an source.
   *
   * @param id the new id (name)
   */
  private void winControl(int id)
  {
    this.id = id;
    hasControl = true;
  }

  /**
   * The openALSource lose it's control over the source.
   */
  protected void loseControl(){
    hasControl = false;
  }

  /**
   * Returns true if the openALSource has the control over a source.
   *
   * @return true if the openALSource has the control over a source
   */
  public boolean hasControl()
  {
    return hasControl;
  }

  public int getPropi(int prop)
  {
    return alGetSourcei(id, prop);
  }

  public float getPropf(int prop)
  {
    return alGetSourcef(id, prop);
  }

  public void setPropi(int prop, int value)
  {
    alSourcei(id, prop, value);
  }
  
  public void setPropf(int prop, FloatBuffer value)
  {
    alSource(id, prop, value);
  }

  public void setPropf(int prop, float value)
  {
    alSourcef(id, prop, value);
  }

  public void setProp3f(int prop, float value1, float value2, float value3)
  {
    alSource3f(id, prop, value1, value2, value3);
  }

  public void setPosition(float x, float y, float z)
  {
    alSource3f(id, AL_POSITION, x, y, z);
  }
  
  public void setPosition(FloatBuffer buffer)
  {
    alSource(id, AL_POSITION, buffer);
  }
  
  public void setVelocity(float x, float y, float z)
  {
    alSource3f(id, AL_VELOCITY, x, y, z);
  }
  
  public void setVelocity(FloatBuffer buffer)
  {
    alSource(id, AL_VELOCITY, buffer);
  }
  
  public void setPitch(float x, float y, float z)
  {
    alSource3f(id, AL_PITCH, x, y, z);
  }
  
  public void setPitch(float value)
  {
    alSourcef(id, AL_PITCH, value);
  }
  
  public void setPitch(FloatBuffer buffer)
  {
    alSource(id, AL_PITCH, buffer);
  }
  
  public void setGain(float x, float y, float z)
  {
    alSource3f(id, AL_GAIN, x, y, z);
  }
  
  public void setGain(float value)
  {
    alSourcef(id, AL_GAIN, value);
  }
  
  public void setGain(FloatBuffer buffer)
  {
    alSource(id, AL_GAIN, buffer);
  }
  
  public void setLooping(boolean value)
  {
	  if(value)
	  {
		  alSourcei(id, AL_LOOPING, AL_TRUE);
	  }else{
		  alSourcei(id, AL_LOOPING, AL_FALSE);
	  }
  }

  /**
   * Start playing the wave file.
   *
   * @param openALWave the wave file.
   */
  public void play(OpenALWave openALWave){
    // set up source input
	  int state = getPropi(AL_SOURCE_STATE);
	  if(state != AL_PLAYING && state != AL_PAUSED)
      {
	    alSourcei(id, AL_BUFFER, openALWave.id);
	    //System.out.println("ID: " + id + " OPen ID: " + openALWave.id);
	    OpenALUtils.checkError();
	
	    // play source 0
	    alSourcePlay(id);
	    //    
	    OpenALUtils.checkError();
      }
  }

  public void pause(){
    alSourcePause(id);
  }

  public void stop(){
    alSourceStop(id);
  }

  public void rewind(){
    alSourceRewind(id);
  }

  public void dispose(){
  }

  public String toString(){
    return "ID: " + id + ", HasControl: " + (hasControl ? "yes" : "no");
  }

	
}
